#include <stdio.h>  
#include <winsock2.h>  
#include <process.h>
#include <vector>
#pragma comment(lib,"ws2_32.lib")  


//-------------协议号定义-----------
#define CMD_ONLINE_DATA 10  //在线信息
#define CMD_MSG         1   //发送消息

char sendBuffer[1024] = { 0 };
char name[20];

//消息记录
struct MessageRecord {
    char from[20];
    char to[20];
    char data[1024];
};

//用户信息
typedef struct {
    char id;
    char name[20];
} UserInfo;

UserInfo selfInfo;      //自己信息
std::vector<UserInfo> usersInfo;    //其他用户信息
std::vector<MessageRecord> record;  //聊天记录


WSADATA wsaData = { 0 };///存放套接字信息,WSADATA结构被用来保存AfxSocketInit函数返回的WindowsSockets初始化信息。  
SOCKET ClientSocket = INVALID_SOCKET;///客户端套接字   
SOCKADDR_IN ServerAddr = { 0 };///服务端地址  
USHORT uPort = 18000;///服务端端口 

UserInfo* getUserInfoByid(char id) {
    for (int i = 0; i < usersInfo.size(); ++i) {
        if (id == usersInfo[i].id) {
            return &usersInfo[i];
        }
    }
    return NULL;
}

//保存消息记录
void SaveRecord(char from, char to, char* data, int datalen) {
    if (from == to)return;  //自己给自己发的消息不保留

    UserInfo* formInfo = getUserInfoByid(from);
    UserInfo* targetInfo = getUserInfoByid(to);

    char fileName[32] = {};
    sprintf(fileName, "%s.txt", selfInfo.name);
    FILE* file = fopen(fileName, "a+");

    if (formInfo && targetInfo) {
        MessageRecord msginfo;
        memset(&msginfo, 0, sizeof(msginfo));
        memcpy(msginfo.from, formInfo->name, sizeof(formInfo->name));
        memcpy(msginfo.to, targetInfo->name, sizeof(targetInfo->name));
        memcpy(msginfo.data, data, datalen);
        record.push_back(msginfo);

        char buffer[2048] = {};
        int len = sprintf(buffer, "%s->%s:  %s\n", msginfo.from, msginfo.to, msginfo.data);
        fwrite(buffer, len, 1, file);
    }
    fclose(file);

}

void ParseMsg(char* data, int len) {
    if (len>0)
    {
        char cmd = data[0]; //协议号
        switch (cmd) {
        case CMD_MSG:   //聊天消息
            MessageRecord msgInfo;
            SaveRecord(data[1], selfInfo.id, data + 2, len-2);

            break;
        case CMD_ONLINE_DATA:   //用户更新信息
            usersInfo.clear();      //清空用户数据
            int idx = 0;
            char* p = data + 1;
            while (idx < len-1) {
                UserInfo info;
                memset(&info, 0, sizeof(UserInfo));
                info.id = p[idx];       //获得id
                memcpy(info.name, p + idx + 2, p[idx+1]);//获得名字
                idx += p[idx + 1] + 2;
                usersInfo.push_back(info);
            }
            break;
        }
    }
    
}



unsigned __stdcall THRE_RECV(void* s) {
    SOCKET ClientSocket = *(SOCKET*)(s);
    char buffer[2048] = {};
    while (1) {
        //接收消息  
        int len = recv(ClientSocket, buffer, sizeof(buffer), 0);
        if (SOCKET_ERROR == len) {
            printf("send failed with error code: %d\n", WSAGetLastError());
            closesocket(ClientSocket);
            WSACleanup();
            return -1;
        }
        ParseMsg(buffer, len);
    }
    return 0;
}



void ProcessPrintUsers(){
    printf("--------current online users---------\n");
    for (int i = 0; i < usersInfo.size(); ++i) {
        if (usersInfo[i].id!= selfInfo.id)
        {
            printf("\t%d  %s\n", usersInfo[i].id, usersInfo[i].name);
        }
    }
    printf("\n");
}

void ProcessSendMsg(char* buffer,int len) {
    ProcessPrintUsers();

    //输入要发送对象的id
    int id = -1;
    printf("input target id: ");
    scanf("%d", &id);
    memcpy(buffer, &id, 1);     

    //输入消息内容
    printf("input the message: ");
    scanf("%s", buffer + 1);

    send(ClientSocket, buffer, strlen(buffer),0);

    //保存记录
    SaveRecord(selfInfo.id, id, buffer + 1, strlen(buffer + 1));
}

//打印聊天记录
void ProcessPrintRecord(){
    printf("--------message record---------\n");
    for (int i = 0;i<record.size();++i)
    {
        printf("\t%s->%s:  %s\n", record[i].from, record[i].to, record[i].data);
    }
    printf("\n");
}

int main() {
     

    ///初始化套接字  
    if (WSAStartup(MAKEWORD(2, 2), &wsaData))///该函数的第一个参数指明程序请求使用的Socket版本，其中高位字节指明副版本、低位字节指明主版本  
    ///第二个参数返回请求的socket版本信息  
    {
        printf("WSAStartup failed with error code: %d\n", WSAGetLastError());
        return -1;
    }
    ///判断套接字版本  
    if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
        printf("wVersion was not 2.2\n");
        return -1;
    }
    ///创建套接字  
    ClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);///AF_INET代表一个地址族,SOCK_STREAM表示为TCP协议的流服务,IPPROTO_TCP的值为6  
    ///printf("%d\n",IPPROTO_TCP);  
    if (ClientSocket == INVALID_SOCKET) {
        printf("socket初始化失败并返回错误代码: %d\n", WSAGetLastError());
        return -1;
    }
    ///输入服务器IP  
    printf("Please input the server's IP:");
    char IP[32] = { 0 };
    scanf("%s",IP);
    ///输入聊天的用户名  
    printf("Please input the Client's username:");
   
    memset(selfInfo.name, 0, sizeof(selfInfo.name));
    scanf("%s", selfInfo.name);
    ///设置服务器地址，填充服务器地址的结构  
    ServerAddr.sin_family = AF_INET;
    ServerAddr.sin_port = htons(uPort);///服务器端口  
    ServerAddr.sin_addr.S_un.S_addr = inet_addr(IP);///服务器地址  

    printf("Connecting...........\n");
    ///连接服务器  
    if (SOCKET_ERROR == connect(ClientSocket, (SOCKADDR*)&ServerAddr, sizeof(ServerAddr))) {
        printf("Connect failed with error code: %d \n", WSAGetLastError());
        closesocket(ClientSocket);
        WSACleanup();
        return -1;
    }
    printf("Successfuuly got a connection from IP:%s Port:%d\n\n\n\n", inet_ntoa(ServerAddr.sin_addr), htons(ServerAddr.sin_port));
    
    //发送名字给服务器
    int len = send(ClientSocket, selfInfo.name, strlen(selfInfo.name), 0);
    if (SOCKET_ERROR == len) {
        printf("send failed with error code: %d\n", WSAGetLastError());
        closesocket(ClientSocket);
        WSACleanup();
        return -1;
    }

    //接收服务器发过来的id号
    len = recv(ClientSocket, &selfInfo.id, sizeof(selfInfo.id), 0);
    if (SOCKET_ERROR == len) {
        printf("receive failed with error code: %d\n", WSAGetLastError());
        closesocket(ClientSocket);
        WSACleanup();
        return -1;
    }
    
    //开启一个线程用于接收数据
    _beginthreadex(NULL, 0, &THRE_RECV, &ClientSocket, NULL, 0);
    
    
    while (1) {
        memset(sendBuffer, 0, sizeof(sendBuffer));
        //发送消息
        printf("-------------Menu----------\n");
        printf("1.send message\n");
        printf("2.print message\n");
        printf("3.print users\n");
        printf("4.quit\n");

        int cmd = 0;
        scanf("%d", &cmd);
        switch (cmd) {
        case 1:
            ProcessSendMsg(sendBuffer, sizeof(sendBuffer));//执行发送消息流程
            break;
        case 2:
            ProcessPrintRecord();
            break;
        case 3:
            ProcessPrintUsers();
            break;
        case 4:
            return -1;
            break;
        }

    }
    closesocket(ClientSocket);
    WSACleanup();
    system("pause");
    return 0;
}